package com.ruoyi.eqmonitor.dispose.task;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.eqmonitor.dispose.domain.ExteriorSite;
import com.ruoyi.eqmonitor.dispose.domain.ExteriorSiteMonitorData;
import com.ruoyi.eqmonitor.dispose.service.ExteriorSiteMonitorDataService;
import com.ruoyi.eqmonitor.dispose.service.ExteriorSiteService;
import com.ruoyi.eqmonitor.utils.Constant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 同步对接进来的微站数据
 */
@Slf4j
@Component
@Profile("prod")
public class SyncExteriorSiteMonitorDataTask {

    @Value("${exterior.site.url}")
    private String url;

    /** 接口id */
    @Value("${exterior.site.jkId}")
    private String jkId;

    /** 接口授权码 */
    @Value("${exterior.site.jkSqm}")
    private String jkSqm;

    /** 接口用户名 */
    @Value("${exterior.site.jkYhm}")
    private String jkYhm;

    /** 交换标识码中的验证码 */
    @Value("${exterior.site.verification-code}")
    private String verificationCode;

    @Resource
    private ExteriorSiteService exteriorSiteService;

    @Resource
    private ExteriorSiteMonitorDataService exteriorSiteMonitorDataService;

    /**
     * 每小时执行一次 将站点数据落入mysql
     * SpringBoot 默认是定时任务同步执行 所以不会出现并发问题
     * 设备的数据回传时间是每4小时回传一次,
     * 为了防止数据的不一致, 我们采用一次请求请求2天数据,进行增改
     */
    @Scheduled(cron = "0 0 0/1 * * ?")
    public void flushExteriorSiteMonitorData() {
        DateTime today = DateUtil.date();
        String startDate = DateUtil.beginOfDay(DateUtil.offsetDay(today, -1)).toString();
        String endDate = DateUtil.endOfDay(today).toString();
        getSiteMonitorDataByDate(startDate, endDate);
    }

    public void getSiteMonitorDataByDate(String startDate, String endDate) {
        List<ExteriorSite> list = exteriorSiteService.list();
        List<String> siteCodes = list.stream().map(ExteriorSite::getSiteCode).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(siteCodes)) {
            String requestTime = DateUtil.format(new Date(), "yyyymmddHHmmss");

            Map<String, Object> body = new HashMap<>();

            body.put("startDate", startDate);
            body.put("endDate", endDate);
            body.put("siteCodes", siteCodes);

            Map<String, Object> queryJsonData = new HashMap<>();
            // 具体查询信息
            queryJsonData.put("body", body);
            //交换标识码 交换识别码是每次数据交互的唯一标识， 14 位时间编码+8 位数据流水码+8位验证码。 格式如：201801011113140000000112345678
            queryJsonData.put("exchangeCode", requestTime.concat("00000000").concat(verificationCode));
            // 交换类型 20 查询数据 21 查询结果数据
            queryJsonData.put("exchangeType", "21");
            // 上报数据时间、查询数据请求时间 格式为 yyyymmddhhmiss
            queryJsonData.put("requestTime", requestTime);

            Map<String, Object> bodyParam = new HashMap<>();
            bodyParam.put("jkId", jkId);
            bodyParam.put("jkSqm", jkSqm);
            bodyParam.put("jkYhm", jkYhm);
            bodyParam.put("queryJsonData", queryJsonData);
            log.info("开始获取 {} ~ {} 的微站数据, 参数: \n {}", startDate, endDate, bodyParam);

            String post = HttpUtil.post(url, JSONUtil.toJsonStr(bodyParam));

            if (!JSONUtil.isJsonObj(post)) {
                log.error("获取微站实时数据失败: {}", post);
                return;
            }

            JSONObject jsonObject = JSONUtil.parseObj(post);
            if (!"0".equals(jsonObject.getStr("code"))) {
                log.error("请求微站实时数据响应失败: {}", post);
                return;
            }

            if (!JSONUtil.isJsonArray(jsonObject.getStr("data"))) {
                log.error("获取微站实时数据, data数据不符合规范: {}", post);
                return;
            }

            JSONArray data = jsonObject.getJSONArray("data");

            log.info("微站实时数据 {} ~ {} : \n {}", startDate, endDate, data);

            if (data != null && !data.isEmpty()) {
                // 刚获取到的最新数据
                List<ExteriorSiteMonitorData> currentDataList = data.toList(ExteriorSiteMonitorData.class);
                // 获取原有数据
                List<ExteriorSiteMonitorData> oldDataList = exteriorSiteMonitorDataService.
                        list(Wrappers.<ExteriorSiteMonitorData>lambdaQuery()
                                .between(ExteriorSiteMonitorData::getDataTime, startDate, endDate));

                List<ExteriorSiteMonitorData> saveData = new ArrayList<>();
                currentDataList.forEach(item -> {
                    // 站点编号相等 && 因子编码相等 && 时间一致 则视为同一条数据
                    ExteriorSiteMonitorData oldData = CollectionUtil.findOne(oldDataList, o ->
                            StrUtil.equals(o.getSiteCode(), item.getSiteCode()) &&
                                    StrUtil.equals(o.getParamCode(), item.getParamCode()) &&
                                    DateUtil.compare(o.getDataTime(), item.getDataTime()) == 0);

                    if (oldData != null) {
                        item.setId(oldData.getId());
                    }
                    Constant.SiteMonitorInfo monitorInfo = Constant.SiteMonitorInfo.getByCode(item.getParamCode());
                    item.setParamName(monitorInfo == null ? "未知" : monitorInfo.getName());
                    saveData.add(item);
                });

                // 批量新增或更新数据
                exteriorSiteMonitorDataService.saveOrUpdateBatch(saveData);
            }
        }
    }
}
